import { _decorator, Component, Node, SkeletalAnimation } from 'cc';
import { Gun } from './Items/Gun';
import { Item } from './Items/Item';
import { Melee } from './Items/Melee';
import { GamerController } from './GamerController';
import { PoolManager } from '../../Scripts/Framework/Managers/PoolManager';
import { Weapon } from './Items/Weapon';
import { ItemBox } from './ItemBox';
import Events from '../../Scripts/Framework/Utils/Events';
import { EventName } from '../../Scripts/Framework/Const/EventName';
import NodeUtil from '../../Scripts/Framework/Utils/NodeUtil';
import { Heal } from './Items/Heal';
import { Armor } from './Items/Armor';
import { Pack } from './Items/Pack';
import { Module } from './Items/Module';
import { Ammo } from './Items/Ammo';
import { Adorn } from './Items/Adorn';
import { GameUI } from './GameUI';
import { InGameManager } from './Managers/InGameManager';
const { ccclass, property } = _decorator;

@ccclass('GamerBackPack')
export class GamerBackPack extends Component {

    private curWeapon: Weapon = null;
    public get CurWeapon(): Weapon { return this.curWeapon; }
    public set CurWeapon(value: Weapon) {
        this.curWeapon = value;
        if (!value || value instanceof Melee) this.getComponent(GamerController).animationController.setValue("WeaponType", 2);
        else if (value instanceof Gun) {
            this.getComponent(GamerController).animationController.setValue("WeaponType", value.type == 0 ? 0 : 1);
            this.getComponent(GamerController).curSpread = value.spread;
        }
        let slot = this.weaponSlots[4];
        if (slot.children[0]) PoolManager.PutNode(slot.children[0]);
        if (value) PoolManager.GetNodeByBundle("MainPack", value.prefabUrl, slot).then((value) => { value.layer = this.getComponent(GamerController).type === 'PlayerController' ? 1 << 5 : 1 << 3; });
        this.getComponent(GamerController).animationController.setValue("Rate", this.CurWeapon?.rate);
        if (this.getComponent(GamerController).type === 'PlayerController') Events.emit(EventName.PlayerWeaponCheck, value);
    }

    pack: Pack;
    public get MaxItems(): number {
        return 10 + (this.pack ? this.pack.level * 5 : 0);
    }
    private containBox: ItemBox = null;
    public get ContainBox(): ItemBox {
        return this.containBox;
    }
    public set ContainBox(value: ItemBox) {
        this.containBox = value;
        if (this.containBox) this.StartGetItemBox();
        else this.EndGetItemBox();
        if (this.getComponent(GamerController).type === 'PlayerController') Events.emit(EventName.PlayerBoxCheck);
    }



    switchWeapon: Weapon;
    melee: Melee = null;
    guns: Gun[] = [null, null, null];
    armors: Armor[] = [null, null];
    weaponSlots: Node[] = [];
    items: Item[] = [];

    protected onLoad(): void {
    }

    start() {

    }

    update(deltaTime: number) {

    }

    Init() {
        if (this.node.children[0]) {
            let strs = ["Pistol", "Gun1", "Gun2", "Melee", "Hand"];
            let sockets: Node[] = [];
            for (let i = 0; i < strs.length; i++) {
                const element = strs[i];
                sockets.push(NodeUtil.GetNode(element, this.node.children[0]));
            }
            if (sockets.length > 0) this.weaponSlots.push(...sockets);
        }
    }

    StartGetItemBox() {
        //暂且禁用ai拾取
        if (this.getComponent(GamerController).type === 'PlayerController') this.schedule(this.GetItemFromBox, 0.5);
    }

    EndGetItemBox() {
        this.unschedule(this.GetItemFromBox);
    }

    GetItemFromBox() {
        if (GameUI.Instance.adornUI.active) return;
        if (this.containBox) {
            for (let i = 0; i < this.containBox.items.length; i++) {
                const element = this.containBox.items[i];
                if (this.CheckBoxItem(element)) {
                    this.GetItem(element);
                    Events.emit(EventName.PlayerBoxCheck);
                    return;
                }
            }
        }
    }

    CheckBoxItem(item: Item): boolean {
        if (item.lastOwner == this) return false;
        if (item instanceof Gun) {
            let guns = this.guns;
            if (!guns[0] && item.type == 0) return true;
            for (let i = 1; i < guns.length; i++) {
                const element = guns[i];
                if (!element) return true;
            }
        }
        else if (item instanceof Module) {
            let guns = this.guns;
            for (let i = 0; i < guns.length; i++) {
                const element = guns[i];
                if (element && element.accessModules[item.type] && (!element.modules[item.type] || element.modules[item.type].figure < item.figure)) return true;
            }
        }
        else if (item instanceof Melee) {
            if (!this.melee) return true;
        }
        else if (item instanceof Armor) {
            let armor = this.armors[item.type];
            if (!armor || armor.durability == 0 || armor.level < item.level || armor.level == item.level && armor.durability < item.durability) return true;
        }
        else if (item instanceof Heal) {
            let heal = this.items.find((value, index, obj) => { if (value.itemName == item.itemName) return value }) as Heal;
            if (!heal) return true;
        }
        else if (item instanceof Ammo) {
            let guns = this.guns;
            let types: number[] = [];
            guns.forEach(element => { if (element) types.push(element.type); });
            for (let i = 0; i < types.length; i++) {
                const element = types[i];
                if (element == item.type) return true;
            }
        }
        else if (item instanceof Pack) {
            if (!this.pack || this.pack.level < item.level) return true;
        }
        else if (item instanceof Adorn) return true;
        return false;
    }

    GetItem(item: Item) {
        //装入背包
        if (item instanceof Gun) {
            if (item.type == 0) this.GetGuns(item, 0);
            else if (this.guns[1] == null) this.GetGuns(item, 1);
            else if (this.guns[2] == null) this.GetGuns(item, 2);
            else if (this.CurWeapon instanceof Gun && this.CurWeapon.type != 0) {
                let num = this.guns.indexOf(this.CurWeapon);
                this.GetGuns(item, num);
            }
            else this.GetGuns(item, 1);
        }
        else if (item instanceof Melee) this.GetMelee(item);
        else if (item instanceof Armor) this.GetArmor(item);
        else if (item instanceof Pack) this.GetPack(item);
        else if (item instanceof Module) this.GetModule(item);
        else if (item instanceof Adorn) return this.GetAdorn(item);
        else this.GetProp(item);
        item.lastOwner = this;
        if (this.getComponent(GamerController).type === 'PlayerController') Events.emit(EventName.PlayerBoxCheck);
    }

    private GetGuns(gun: Gun, num: number) {
        let loseGun = this.guns[num];
        if (loseGun) this.Drop(loseGun);
        else if (this.items.length >= this.MaxItems) {
            if (this.getComponent(GamerController).type === 'PlayerController') Events.emit(EventName.PlayerFullPack);
            return;
        }
        this.guns[num] = gun;
        if (!this.CurWeapon) this.CurWeapon = gun;
        else {
            let slot = this.weaponSlots[num];
            if (slot.children[0]) PoolManager.PutNode(slot.children[0]);
            PoolManager.GetNodeByBundle("MainPack", gun.prefabUrl, slot).then((value) => { value.layer = this.getComponent(GamerController).type === 'PlayerController' ? 1 << 5 : 1 << 3; });
        }
        this.items.unshift(gun);
        if (this.containBox) {
            let num = this.containBox.items.indexOf(gun);
            if (num != -1) {
                this.containBox.items.splice(num, 1);
                this.containBox.CheckSp();
                let controlUI = InGameManager.Instance.controlUI.getComponent("ControlUI") as any;
                controlUI.boxPanel.Init();
                if (this.getComponent(GamerController).type === 'PlayerController') Events.emit(EventName.PlayerBoxCheck);
            }
        }
        if (this.getComponent(GamerController).type === 'PlayerController') Events.emit(EventName.PlayerWeaponData, gun, true);
    }

    private GetMelee(melee: Melee) {
        let dropMelee = this.melee;
        if (dropMelee) this.Drop(dropMelee);
        this.melee = melee;
        let slot = this.weaponSlots[3];
        if (slot.children[0]) PoolManager.PutNode(slot.children[0]);
        if (!this.CurWeapon) this.CurWeapon = melee;
        else {
            PoolManager.GetNodeByBundle("MainPack", melee.prefabUrl, slot).then((value) => { value.layer = this.getComponent(GamerController).type === 'PlayerController' ? 1 << 5 : 1 << 3; });
        }
        this.items.unshift(melee);
        if (this.containBox) {
            let num = this.containBox.items.indexOf(melee);
            if (num != -1) {
                this.containBox.items.splice(num, 1);
                this.containBox.CheckSp();
                let controlUI = InGameManager.Instance.controlUI.getComponent("ControlUI") as any;
                controlUI.boxPanel.Init();
                if (this.getComponent(GamerController).type === 'PlayerController') Events.emit(EventName.PlayerBoxCheck);
            }
        }
        if (this.getComponent(GamerController).type === 'PlayerController') Events.emit(EventName.PlayerWeaponData, melee, true);
    }

    private GetArmor(armor: Armor) {
        let target = this.armors[armor.type];
        if (target) this.Drop(target);
        this.armors[armor.type] = armor;
        if (this.containBox) {
            let num = this.containBox.items.indexOf(armor);
            if (num != -1) {
                this.containBox.items.splice(num, 1);
                this.containBox.CheckSp();
                let controlUI = InGameManager.Instance.controlUI.getComponent("ControlUI") as any;
                controlUI.boxPanel.Init();
                if (this.getComponent(GamerController).type === 'PlayerController') Events.emit(EventName.PlayerBoxCheck);
            }
        }
        if (this.getComponent(GamerController).type === 'PlayerController') Events.emit(EventName.PlayerArmorCheck);
    }

    private GetPack(pack: Pack) {
        if (this.containBox) {
            let num = this.containBox.items.indexOf(pack);
            if (num != -1) this.containBox.items.splice(num, 1);
            if (this.pack) this.containBox.items.push(this.pack);
            this.containBox.CheckSp();
            let controlUI = InGameManager.Instance.controlUI.getComponent("ControlUI") as any;
            controlUI.boxPanel.Init();
            if (this.getComponent(GamerController).type === 'PlayerController') Events.emit(EventName.PlayerBoxCheck);
        }
        this.pack = pack;
        if (this.getComponent(GamerController).type === 'PlayerController') Events.emit(EventName.PlayerPackLevel);
    }

    private GetProp(prop: Item) {
        let item = this.items.find((value, index, obj) => { if (value.itemName == prop.itemName) return value; });
        if (item) {
            if (item.num + prop.num > item.maxNum) {
                prop.num = prop.num - (item.maxNum - item.num);
                item.num = item.maxNum;
                if (this.items.length < this.MaxItems) {
                    this.items.unshift(prop);
                    if (this.containBox) {
                        let num = this.containBox.items.indexOf(prop);
                        if (num != -1) {
                            this.containBox.items.splice(num, 1);
                            this.containBox.CheckSp();
                            if (this.getComponent(GamerController).type === 'PlayerController') Events.emit(EventName.PlayerBoxCheck);
                        }
                    }
                }
                else if (this.getComponent(GamerController).type === 'PlayerController') Events.emit(EventName.PlayerFullPack);
            }
            else {
                item.num += prop.num;
                PoolManager.PutItem(prop);
                if (this.containBox) {
                    let num = this.containBox.items.indexOf(prop);
                    if (num != -1) {
                        this.containBox.items.splice(num, 1);
                        this.containBox.CheckSp();
                        let controlUI = InGameManager.Instance.controlUI.getComponent("ControlUI") as any;
                        controlUI.boxPanel.Init();
                        if (this.getComponent(GamerController).type === 'PlayerController') Events.emit(EventName.PlayerBoxCheck);
                    }
                }
            }
        }
        else if (this.items.length < this.MaxItems) {
            this.items.unshift(prop);
            if (this.containBox) {
                let num = this.containBox.items.indexOf(prop);
                if (num != -1) {
                    this.containBox.items.splice(num, 1);
                    this.containBox.CheckSp();
                    let controlUI = InGameManager.Instance.controlUI.getComponent("ControlUI") as any;
                    controlUI.boxPanel.Init();
                    if (this.getComponent(GamerController).type === 'PlayerController') Events.emit(EventName.PlayerBoxCheck);
                }
            }
        }
        else if (this.getComponent(GamerController).type === 'PlayerController') Events.emit(EventName.PlayerFullPack);
        if (this.getComponent(GamerController).type === 'PlayerController') {
            if (prop instanceof Heal) Events.emit(EventName.PlayerHealUI);
            else if (prop instanceof Ammo) Events.emit(EventName.PlayerWeaponData, prop);
        }
    }

    private GetAdorn(adorn: Adorn) {
        GameUI.Instance.AdornShow(adorn);
        if (this.containBox) {
            let num = this.containBox.items.indexOf(adorn);
            if (num != -1) {
                this.containBox.items.splice(num, 1);
                this.containBox.CheckSp();
                let controlUI = InGameManager.Instance.controlUI.getComponent("ControlUI") as any;
                controlUI.boxPanel.Init();
                if (this.getComponent(GamerController).type === 'PlayerController') Events.emit(EventName.PlayerBoxCheck);
            }
        }
    }

    private GetModule(module: Module) {
        if (this.EquipModule(module)) {
            if (this.containBox) {
                let num = this.containBox.items.indexOf(module);
                if (num != -1) {
                    this.containBox.items.splice(num, 1);
                    this.containBox.CheckSp();
                    if (this.getComponent(GamerController).type === 'PlayerController') Events.emit(EventName.PlayerBoxCheck);
                }
            }
        }
        else if (this.items.length < this.MaxItems) {
            this.items.unshift(module);
            if (this.containBox) {
                let num = this.containBox.items.indexOf(module);
                if (num != -1) {
                    this.containBox.items.splice(num, 1);
                    this.containBox.CheckSp();
                    let controlUI = InGameManager.Instance.controlUI.getComponent("ControlUI") as any;
                    controlUI.boxPanel.Init();
                    if (this.getComponent(GamerController).type === 'PlayerController') Events.emit(EventName.PlayerBoxCheck);
                }
            }
        }
        else if (this.getComponent(GamerController).type === 'PlayerController') Events.emit(EventName.PlayerFullPack);
    }

    EquipModule(module: Module): boolean {
        if (this.CurWeapon instanceof Gun && this.CurWeapon.accessModules[module.type] && (!this.CurWeapon.modules[module.type] || this.CurWeapon.modules[module.type].figure < module.figure)) {
            this.ModuleEquip(module, this.CurWeapon);
            return true;
        }
        let bool = this.CurWeapon instanceof Gun;
        for (let i = 1; i < this.guns.length; i++) {
            const element = this.guns[i];
            if (!element) continue;
            if (bool && this.CurWeapon == element) continue;
            if (element.accessModules[module.type] && (!element.modules[module.type] || element.modules[module.type].figure < module.figure)) {
                this.ModuleEquip(module, element);
                return true;
            }
        }
        let gun = this.guns[0];
        if (!gun) return false;
        if (!(bool && this.CurWeapon == gun) && gun.accessModules[module.type] && (!gun.modules[module.type] || gun.modules[module.type].figure < module.figure)) {
            this.ModuleEquip(module, gun);
            return true;
        }
        return false;
    }

    ModuleEquip(module: Module, gun: Gun) {
        if (gun.modules[module.type]) {
            let target = gun.modules[module.type];
            if (!this.EquipModule(target)) this.items.unshift(target);
        }
        gun.modules[module.type] = module;
        let num = this.items.indexOf(module);
        if (num != -1) this.items.splice(num, 1);
    }

    UnequipModule(module: Module, gun: Gun, isDrop = false) {
        if (gun.modules[module.type]) this.items.unshift(gun.modules[module.type]);
        gun.modules[module.type] = null;
        if (isDrop) this.Drop(module);
    }

    ReequipModule(module: Module, gun1: Gun, gun2: Gun) {
        gun1.modules[module.type] = null;
        gun2.modules[module.type] = module;
    }

    Drop(...items: Item[]) {
        if (!this.containBox) this.containBox = ItemBox.Init(this.node.getWorldPosition());
        this.containBox.items.unshift(...items);
        this.containBox.CheckSp();
        if (this.getComponent(GamerController).type === 'PlayerController') Events.emit(EventName.PlayerBoxCheck);
        if (items.length == 1) {
            let item = items[0];
            if (this.CurWeapon == item) this.CurWeapon = null;
            let num = this.items.indexOf(item);
            if (num != -1) this.items.splice(num, 1);
            if (item instanceof Gun) {
                let num = this.guns.indexOf(item);
                this.guns[num] = null;
                if (this.getComponent(GamerController).type === 'PlayerController') Events.emit(EventName.PlayerDropWeapon, num);
            }
            else if (item instanceof Melee) {
                this.melee = null;
                if (this.getComponent(GamerController).type === 'PlayerController') Events.emit(EventName.PlayerDropWeapon, 3);
            }
            else if (this.getComponent(GamerController).type === 'PlayerController') {
                if (item instanceof Heal) Events.emit(EventName.PlayerHealUI);
                else if (item instanceof Ammo) Events.emit(EventName.PlayerWeaponData, item);
            }
        }
        if (this.getComponent(GamerController).type === 'PlayerController') Events.emit(EventName.PlayerBoxCheck);
    }

    DestroyItem(item: Item) {
        let num = this.items.indexOf(item);
        if (num != -1) {
            this.items.splice(num, 1);
            PoolManager.PutItem(item);
        }
        else console.error("并非该背包的物品！");
    }

    Clear() {
        for (let i = 0; i < this.weaponSlots.length; i++) {
            const element = this.weaponSlots[i].children[0];
            if (element) PoolManager.PutNode(element);
        }
        this.containBox = null;
        this.items = [];
        this.CurWeapon = null;
        this.melee = null;
        this.guns = [null, null, null];
        this.armors = [null, null];
        this.weaponSlots = [];
    }

    IsEmpty(item: Item) {
        if (item.num <= 0) {
            let num = this.items.indexOf(item);
            this.items.splice(num);
        }
    }

    ChooseWeapon() {
        let weapon = this.CurWeapon;
        if (weapon) {
            let slot: Node;
            if (weapon instanceof Gun) {
                let num = this.guns.indexOf(weapon);
                slot = this.weaponSlots[num];
            }
            else if (weapon instanceof Melee) slot = this.weaponSlots[3];
            if (slot) PoolManager.GetNodeByBundle("MainPack", weapon.prefabUrl, slot).then((value) => { value.layer = this.getComponent(GamerController).type === 'PlayerController' ? 1 << 5 : 1 << 3; });
        }

        let slot: Node;
        if (this.switchWeapon instanceof Gun) {
            let num = this.guns.indexOf(this.switchWeapon);
            slot = this.weaponSlots[num];
        }
        else if (this.switchWeapon instanceof Melee) slot = this.weaponSlots[3];
        if (slot) PoolManager.PutNode(slot.children[0]);
        this.CurWeapon = this.switchWeapon;
    }
}


